package com.chianghao.nio.core.handle;

import com.chianghao.nio.core.NioSubReactor;
import com.chianghao.nio.core.handle.http.*;

import java.io.ByteArrayOutputStream;
import java.nio.ByteBuffer;
import java.nio.channels.SelectionKey;
import java.nio.channels.SocketChannel;
import java.nio.charset.Charset;
import java.util.HashMap;
import java.util.Map;

/**
 * @author ChiangHao
 * @date 2022/10/15 16:41
 */
public class ChannelReadThread implements Runnable{

    private SelectionKey key;
    private SocketChannel channel;
    private NioSubReactor subReactor;

    public ChannelReadThread(NioSubReactor subReactor,SelectionKey key, SocketChannel channel){
        this.key = key;
        this.channel = channel;
        this.subReactor = subReactor;
    }

    @Override
    public void run() {
        ByteBuffer readBuffer = ByteBuffer.allocate(1024);
        int read;
        try{

            boolean iscr = false;
            boolean isHeader = true;
            boolean isFirstRow = true;
            // 读取first
            int firstLineSpace = 0;
            ByteArrayOutputStream methodBytes = new ByteArrayOutputStream();
            ByteArrayOutputStream pathBytes = new ByteArrayOutputStream();
            ByteArrayOutputStream protocolBytes = new ByteArrayOutputStream();

            // 读取header
            boolean isReadHeaderName = true;
            ByteArrayOutputStream headerName = new ByteArrayOutputStream();
            ByteArrayOutputStream headerValue = new ByteArrayOutputStream();
            Map<String, HttpHeader> headerMap =  new HashMap<>(20);
            // 读取body内容
            ByteArrayOutputStream body = new ByteArrayOutputStream();

            while ((read = channel.read(readBuffer)) > 0) {
                readBuffer.flip();
                byte[] readByte = new byte[read];
                readBuffer.get(readByte);
                // 获取字节
                for(byte temp:readByte){
                    if(isHeader){
                        if(temp==0x0D){
                            iscr = true;
                            continue;
                        }
                        if(iscr&&temp==0x0A){
                            // 换行
                            if(isFirstRow){
                                isFirstRow =false;
                            }else{
                                // 将header的登记为header集合中
                                String name = new String(headerName.toByteArray());
                                HttpHeader httpHeader = new HttpHeader();
                                httpHeader.setName(name);
                                httpHeader.setValue(headerValue.toByteArray());
                                headerMap.put(name,httpHeader);
                                isReadHeaderName = true;
                                headerName = new ByteArrayOutputStream();
                                headerValue = new ByteArrayOutputStream();
                                if(name.length()==0&&httpHeader.getValue().length==0){
                                    isHeader = false;
                                }
                            }
                        }else{
                            // 不换行
                            if(isFirstRow){
                                if(temp==0x20&&firstLineSpace<2){
                                    firstLineSpace++;
                                }else{
                                    if(firstLineSpace==0){
                                        methodBytes.write(new byte[]{temp});
                                    }else if(firstLineSpace==1){
                                        pathBytes.write(new byte[]{temp});
                                    }else{
                                        protocolBytes.write(new byte[]{temp});
                                    }
                                }
                            }else{
                                if(isReadHeaderName&&temp==0x3A){
                                    isReadHeaderName = false;
                                }else{
                                    if(isReadHeaderName){
                                        headerName.write(new byte[]{temp});
                                    }else{
                                        headerValue.write(new byte[]{temp});
                                    }
                                }
                            }
                        }
                        iscr = false;
                    }else{
                        body.write(new byte[]{temp});
                    }
                }
                readBuffer.clear();
            }

            // 定义解析的编码
            Charset decodeCharset = Charset.forName("UTF-8");

            HttpRequest request = new HttpRequest();
            String protocol = new String(protocolBytes.toByteArray(),decodeCharset);
            String method = new String(methodBytes.toByteArray(),decodeCharset);
            String path = new String(pathBytes.toByteArray(),decodeCharset);
            if(headerMap.containsKey("Content-Type")){
                request.setContentType(
                        new String(headerMap.get("Content-Type").getValue(),"UTF-8").trim());
            }

            if(!protocol.equals("HTTP/1.1")){
                System.out.println("不支持的协议");
            }
            HttpMethod httpMethod = HttpMethod.get(method);
            if(httpMethod==null){
                System.out.println("不支持的mthod");
            }
            request.setMethod(httpMethod);
            request.setVersion(protocol);


            String url = path;
            String queryString="";
            if(path.contains("?")){
                int index = path.indexOf("?");
                url = path.substring(0,index);
                queryString = path.substring(index+1);
                if(queryString!=null&&queryString.length()>0){
                    Map<String,String> queryParams = new HashMap<String,String>();
                    String[] items = queryString.split("&");
                    for(String item:items){
                        if(item.contains("=")){
                            queryParams.put(item.substring(0,item.indexOf("=")),item.substring(item.indexOf("=")+1));
                        }else{
                            queryParams.put(item,null);
                        }
                    }
                    request.setQueryParams(queryParams);
                }
            }
            request.setUrl(url);
            headerMap.forEach((key,value)->{
                if(key==null||key.length()==0){
                    return;
                }
                request.getHeaderMap().put(key,new String(value.getValue(),decodeCharset).trim());
            });
            request.setBody(body.toByteArray());

            HttpResponse response = new HttpResponse();
            HttpRoute httpRoute = this.subReactor.getRouteMap().get(new HttpRequestKey(request.getMethod(),url));
            if(httpRoute==null){
                System.out.println("未找到处理方法");
            }else{
                httpRoute.handle(request,response);
            }


            ChannelContext channelContext = null;
            if(key.attachment()!=null){
                channelContext = (ChannelContext)key.attachment();
                channelContext.setResponse(response);
            }

            if (!subReactor.mutex.hasQueuedThreads()) {
                subReactor.mutex.lock();
                try{
                    subReactor.selector.wakeup();
                    channel.register(subReactor.selector, SelectionKey.OP_WRITE,channelContext);
                }finally {
                    subReactor.mutex.unlock();
                }
            }else{
                channel.register(subReactor.selector, SelectionKey.OP_WRITE,channelContext);
            }
        }catch (Exception e){
            e.printStackTrace();
        }
    }

    private static class HttpHeader {

        private String name;
        private byte[] value;

        public String getName() {
            return this.name;
        }

        public void setName(String name) {
            this.name = name;
        }

        public byte[] getValue() {
            return this.value;
        }

        public void setValue(byte[] value) {
            this.value = value;
        }
    }

}
